﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Xml.Serialization;
using Common;

namespace System.Linq
{
    public static class EnumerableHelper
    {
        /// <summary>
        /// Converts a Enumerable collection to a SerializableDictionary class.
        /// </summary>
        /// <typeparam name="TSource">Enumerable collection</typeparam>
        /// <typeparam name="TKey">The key type.</typeparam>
        /// <typeparam name="TElement">The value type.</typeparam>
        /// <param name="source">Enumerable collection</param>
        /// <param name="keySelector">Key selector function</param>
        /// <param name="elementSelector">Value selector function</param>
        /// <returns>SerializableDictionary type of the enumerable collection.</returns>
        public static SerializableDictionary<TKey, TElement> ToSerializableDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            if (source.isNull()) throw new ArgumentNullException("source");

            SerializableDictionary<TKey, TElement> cur = new SerializableDictionary<TKey, TElement>();

            foreach (TSource item in source)
            {
                cur.Add(keySelector(item), elementSelector(item));
            }

            return cur;
        }

        /// <summary>
        /// Finds an index of a value from a enumerable collection.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="items">Enumerable collection</param>
        /// <param name="predicate">expression to find.</param>
        /// <returns>Index location from the collection.</returns>
        public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate)
        {
            if (items == null) throw new ArgumentNullException("items");
            if (predicate == null) throw new ArgumentNullException("predicate");

            int retVal = 0;
            foreach (var item in items)
            {
                if (predicate(item)) return retVal;
                retVal++;
            }
            return -1;
        }

        /// <summary>
        /// Finds an index of a value from a enumerable collection.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="items">Enumerable collection</param>
        /// <param name="item">Item value to find.</param>
        /// <returns>Index location from the collection.</returns>
        public static int IndexOf<T>(this IEnumerable<T> items, T item)
        {
            return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i));
        }

        /// <summary>
        /// Finds duplicates in a enumerable collection.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="source">Enumerable collection</param>
        /// <returns>
        /// A enumerable collection of the duplicates. Collection will
        /// have a count/length of zero, if no duplicates.
        /// </returns>
        public static IEnumerable<T> GetDuplicates<T>(this IEnumerable<T> source)
        {
            HashSet<T> itemsSeen = new HashSet<T>();
            HashSet<T> itemsYielded = new HashSet<T>();

            foreach (T item in source)
            {
                if (!itemsSeen.Add(item))
                {
                    if (itemsYielded.Add(item))
                    {
                        yield return item;
                    }
                }
            }
        }

        //TODO: Finish
        public static T Get<TSource, T>(this IEnumerable<TSource> source, int Index)
        {
            if (source == null) return GenericType.CreateNew<T>();
            if (source.Count() < 1) return GenericType.CreateNew<T>();

            int iIndex = 0;
            object RetObj = null;

            source.ForEach(p =>
                {
                    if (iIndex == Index)
                    {
                        // Set variable or return variable
                        
                        return;
                    }
                    iIndex++;
                }
            );

            return GenericType.CreateNew<T>();
        }

        public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
        {
            foreach(var x in source)
                action(x);
        }

        //TODO: Finish
        public static void For<TSource, TResult>(this IEnumerable<TSource> source, int fromInclusive, int toExclusive, Func<int, TResult> execAction)
        {
            for (int i = fromInclusive; i < toExclusive; i++)
            {
                    execAction(source.ge);
            }
        }

    }
}
